package edu.pku.sei.autounit.generator;

import java.util.HashMap;
import java.util.Map;

import edu.pku.sei.autounit.core.Variable;
import edu.pku.sei.autounit.core.VariableFactory;
import edu.pku.sei.autounit.core.VariableGenerator;
import edu.pku.sei.autounit.filter.Filter;
import edu.pku.sei.autounit.reflect.Context;
import edu.pku.sei.autounit.reflect.Type;
import edu.pku.sei.autounit.reflect.java.JavaClass;
import edu.pku.sei.autounit.reflect.java.JavaInterface;
import edu.pku.sei.autounit.reflect.java.TypeFactory;
import edu.pku.sei.autounit.util.NameFactory;
import edu.pku.sei.autounit.util.Properties;
import edu.pku.sei.autounit.util.Statements;

public class MapGenerator implements VariableGenerator{

	
	public Variable generate(Type type, String name, VariableFactory vf,
			NameFactory nf) {
		
		if(type instanceof Context){
			TypeFactory tf = new TypeFactory();
			
			Type hashMap = new JavaClass(HashMap.class,((Context) type).getContexts(),tf);
			if(type.isAssignableFrom(hashMap)){
				Variable v =null;
				if(type.equals(hashMap))
					v = vf.getVariableContinue(hashMap, name, nf, this);
				else
					v = vf.getVariableContinue(hashMap, nf.getName("HashMap", NameFactory.TEMP), nf, this);
				return new MapVariable(type,name,v,vf,nf);
			}
			
			if(((Context) type).getContexts().length!=2)
				return null;
			Type map = new JavaInterface(Map.class,((Context) type).getContexts(),tf);
			if(map.isAssignableFrom(type)){
				Variable v = vf.getVariableContinue(type, name, nf, this);
				return new MapVariable(type,name,v,vf,nf);
			}
		}
		return null;
	}

	
	public Variable generate(Type type, String name, Filter fliter,
			VariableFactory vf, NameFactory nf) {
		// TODO Auto-generated method stub
		return null;
	}
	
	static class MapVariable implements Variable{

		private Map<Variable,Variable> vmap;
		private Type type;
		private Variable variable;
		private String name;
		public MapVariable(Type type,String name ,Variable variable,VariableFactory vf,NameFactory nf) {
			this.variable = variable;
			this.type = type;
			this.name = name;
			vmap = new HashMap<Variable, Variable>();
			int size = Properties.getMapSize();
			Type [] contexts = ((Context) type).getContexts();
			if(contexts.length==2){
				for(int i = 0 ;i<size;i++){
					Variable key = vf.getVariable(contexts[0], 
							nf.getName(contexts[0].getFullName(), NameFactory.KEY), vf, nf);
					Variable value = vf.getVariable(contexts[1], 
							nf.getName(contexts[1].getFullName(), NameFactory.VALUE), vf, nf);
					vmap.put(key, value);
				}
			}
			
		}

		
		public Statements getInitCode(Map<String,String> map){
			
			Statements s =new Statements();

			s.merge(variable.getInitCode(map));
			if(!variable.getValue().equals(name))
				s.insertStatement(type.getName(map)+" "+name+" = "+variable.getValue()+";");
				
			for(Map.Entry<Variable, Variable> e : vmap.entrySet()){
				s.merge(e.getKey().getInitCode(map));
				s.merge(e.getValue().getInitCode(map));
			}
			
			for(Map.Entry<Variable, Variable> e : vmap.entrySet()){
				StringBuffer sb = new StringBuffer();
				sb.append(name);
				sb.append(".put(");
				sb.append(e.getKey().getValue());
				sb.append(",");
				sb.append(e.getValue().getValue());
				sb.append(");");
				s.insertStatement(sb.toString());
			}
			return s;
		}

		
		public String getValue() {
			return name;
		}

		
		public Type getType() {
			return type;
		}
	}

}
